home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Panorama / Panorama - Disk 19D (1987-07-22)(Pacific North-West Amigas Club)[WB].zip / Panorama - Disk 19D (1987-07-22)(Pacific North-West Amigas Club)[WB].adf / PipeHandler1.2 / pipe-handler.c < prev    next >
C/C++ Source or Header  |  1987-06-28  |  11KB  |  378 lines

  1. /****************************************************************************
  2. **  File:       pipe-handler.c
  3. **  Program:    pipe-handler - an AmigaDOS handler for named pipes
  4. **  Version:    1.2
  5. **  Author:     Ed Puckett      qix@mit-oz
  6. **
  7. **  Copyright 1987 by EpAc Software.  All Rights Reserved.
  8. **
  9. **  History:    05-Jan-87       Original Version (1.0)
  10. **        07-Feb-87    Added shared locks for individual pipes.
  11. **                PIPEDATA structure modified to include
  12. **                 a FileLock structure.
  13. **        07-Feb-87    Added #if's forautomatic pipe naming "feature"
  14. **                 for pipes specified with empty names.
  15. **        12-Feb-87    Added ParentDir packet handling.
  16. **        12-Feb-87    Fixed bug in OpenPipe() and PipeLock():
  17. **                 they previously ignored the lock passed in
  18. **                 packet.  Bug uncovered when pipes became
  19. **                 lockable, and thus assignable.
  20. **        27-Mar-87    Added the case for PipeDupLock().  This was
  21. **                 missing in the original version!
  22. **        28-Mar-87    Added code to handler() to remove ':' from
  23. **                 end of handler name.  This caused problems
  24. **                 with Examine(); it expects no ending  ':'.
  25. */
  26.  
  27. #include   <libraries/dos.h>
  28. #include   <libraries/dosextens.h>
  29. #include   <libraries/filehandler.h>
  30. #include   <exec/exec.h>
  31.  
  32. #include   "pipelists.h"
  33. #include   "pipename.h"
  34. #include   "pipebuf.h"
  35. #include   "pipecreate.h"
  36. #include   "pipesched.h"
  37. #include   "pipe-handler.h"
  38.  
  39. #if PIPEDIR
  40. # include   "pipedir.h"
  41. #endif PIPEDIR
  42.  
  43. #ifdef DEBUG
  44. # include   "pipedebug.h"
  45. #endif DEBUG
  46.  
  47.  
  48.  
  49. /*---------------------------------------------------------------------------
  50. ** pipe-handler.c
  51. ** --------------
  52. ** This is the main module for the handler.  Handlers are started with
  53. ** register D1 containing a BPTR to a startup packet, which in turn contains
  54. ** (BCPL) pointers to the name and DeviceNode.  Since the entry, handler(),
  55. ** expects a byte address of the startup packet, an assembly language startup
  56. ** must be used to convert the BCPL pointer, and pass it on the stack.
  57. **
  58. ** Problems arise if a handler tries to do I/O via the DOS functions Open(),
  59. ** Close(), Read() and Write().  DOS sends request packets to the handler
  60. ** via its DOS port (the one whose address forms the process ID).  This is
  61. ** also the port used by the I/O functions.  Therefore, if a request comes,
  62. ** and then an Open() call is performed, DOS will send a request packet for
  63. ** the open and erroneously pick up the request packet meant for the handler
  64. ** as its reply.  A crash ensues.
  65. **
  66. ** This is the reason for the I/O functions in pipedebug.c.  They implement
  67. ** the regualar I/O calls, but use a different ReplyPort.  With no debugging,
  68. ** these functions are unneeded, since all of the handler's normal I/O is
  69. ** performed asynchronously, using PutMsg().
  70. **
  71. ** An alternate solution is to patch the handler's Task field with a new port
  72. ** instead of the handler's DOS port.  This works, except that DOS always
  73. ** sends the initial request packets to the DOS port (when the handler is
  74. ** first started).  This is probably because DeviceProc(), upon seeing that
  75. ** the handler has not yet been loaded, returns the result from its call to
  76. ** CreateProc() for the handler process.  Only on subsequent calls to
  77. ** DeviceProc() will the patched field be returned.  The upshot of this is
  78. ** that an alternate port can be used for handler requests, but there are
  79. ** always an unspecified number that may come over the DOS port regardless.
  80. ** Note that since not all handlers patch their Task field (because they want
  81. ** to be restarted each time), DOS is doing the "right" thing, or at least
  82. ** the best it can.
  83. **
  84. ** Visible Functions
  85. ** -----------------
  86. **    void      handler   (StartPkt)
  87. **    PIPEDATA  *FindPipe (name)
  88. **
  89. ** Macros (in pipe-handler.h)
  90. ** --------------------------
  91. **    BPTRtoCptr (Bp)
  92. **    CptrtoBPTR (Cp)
  93. **    ReplyPkt   (pkt)
  94. **
  95. ** Local Functions
  96. ** ---------------
  97. **    struct DosPacket  *GetPkt (port)
  98. */
  99.  
  100.  
  101.  
  102. /*---------------------------------------------------------------------------
  103. ** HandlerName  : passed as a BSTR in startup packet Arg1, our device name.
  104. **        Everything from the ':' and beyond is removed.
  105. **        Used by PipeExamine() for the handler's "directory" name.
  106. **
  107. ** DevNode    : passed as a BPTR in startup packet Arg3.  This is a pointer
  108. **        to our DeviceNode entry in the system device list (DevInfo).
  109. **
  110. ** Pipeort    : our DOS MsgPort, as well as our process ID.  See above for
  111. **        notes about why we can't let DOS use this.
  112. **
  113. ** pipelist    : the list of currently existing pipes.  PIPEDATA nodes are
  114. **        linked into this list.
  115. **
  116. ** tapwaitlist    : the list of requests waiting on tap opens/closes/writes.
  117. **        WAITINGDATA nodes are linked into this list.  See pipesched.c
  118. **        and pipecreate.c.
  119. **
  120. ** TapReplyPort    : this is the MsgPort to which tap I/O replys are returned.
  121. **
  122. ** SysBase,
  123. ** DOSBase    : Standard system library pointers.  Since we don't have the
  124. **        usual startup code, we must initialize these ourselves.
  125. **
  126. ** PipeDate    : If compiled with PIPEDIR true, the handler responds to some
  127. **        directory-like actions.  This is the date for the entire
  128. **        handler, i.e., the directory date.  The flag UPDATE_PIPEDATE
  129. **        controls whether this date is updated with each pipe access
  130. **        (true) or not (false).  See SetPipeDate() and PipeExamine().
  131. */
  132.  
  133. char               HandlerName[30];
  134. struct DeviceNode  *DevNode   =  NULL;
  135. struct MsgPort     *PipePort  =  NULL;
  136.  
  137. PIPELISTHEADER     pipelist;
  138.  
  139. PIPELISTHEADER     tapwaitlist;
  140. struct MsgPort     *TapReplyPort  =  NULL;
  141.  
  142. struct Library     *SysBase  =  NULL;
  143. struct Library     *DOSBase  =  NULL;
  144.  
  145. #if PIPEDIR
  146.   struct DateStamp   PipeDate;
  147. #endif PIPEDIR
  148.  
  149.  
  150.  
  151. /*---------------------------------------------------------------------------
  152. ** Performs initialization, replies to startup packet, and dispatches
  153. ** incoming request packets to the apropriate functions.  The TapReplyPort is
  154. ** also monitored for returning requests which were sent out by the handler.
  155. ** These returned requests are routed to HandleTapReply().
  156. **      Our DeviceNode Task field is patched with our process ID so that this
  157. ** process is used for subsequent handler requests.  The function exits only
  158. ** if there is some initialization error.
  159. */
  160.  
  161. void  handler (StartPkt)
  162.  
  163. struct DosPacket  *StartPkt;
  164.  
  165. { char              *cp;
  166.   struct Task       *Task;
  167.   ULONG             PipeMask, TapReplyMask, WakeupMask, SigMask;
  168.   struct DosPacket  *pkt, *GetPkt();
  169.   void              OpenPipe(), ClosePipe();
  170.  
  171.  
  172.   SysBase= AbsExecBase;
  173.   if ((DOSBase= OpenLibrary (DOSNAME, 0)) == NULL)
  174.     goto QUIT;
  175.  
  176.   BSTRtoCstr (BPTRtoCptr (StartPkt->dp_Arg1), HandlerName, sizeof (HandlerName));
  177.   for (cp= HandlerName; *cp != '\0'; ++cp)
  178.     if (*cp == ':')      /* remainder of handler's first refernece follows */
  179.       { *cp= '\0';
  180.         break;
  181.       }
  182.  
  183.   Task= FindTask (0);
  184.   PipePort= (struct MsgPort *) ((ULONG) Task + sizeof (struct Task));
  185.   ((struct Process *) Task)->pr_CurrentDir= 0;     /* initial file system root */
  186.  
  187.   if ((TapReplyPort= CreatePort (NULL, PipePort->mp_Node.ln_Pri)) == NULL)
  188.     goto QUIT;
  189.  
  190. #ifdef DEBUG
  191.   if (! InitDebugIO (PipePort->mp_Node.ln_Pri))
  192.     goto QUIT;
  193. #endif DEBUG
  194.  
  195.  
  196.   PipeMask=     (1L << PipePort->mp_SigBit);
  197.   TapReplyMask= (1L << TapReplyPort->mp_SigBit);
  198.   WakeupMask=   (PipeMask | TapReplyMask);
  199.  
  200.   DevNode= (struct DeviceNode *) BPTRtoCptr (StartPkt->dp_Arg3);
  201.   DevNode->dn_Task= PipePort;
  202.  
  203.   InitList (&pipelist);
  204.   InitList (&tapwaitlist);
  205.  
  206. #if PIPEDIR
  207.   (void) DateStamp (&PipeDate);
  208. #endif PIPEDIR
  209.  
  210.   ReplyPkt (StartPkt);
  211.  
  212.  
  213. LOOP:
  214.   SigMask= Wait (WakeupMask);
  215.  
  216.   if (SigMask & TapReplyMask)
  217.     while ((pkt= GetPkt (TapReplyPort)) != NULL)
  218.       HandleTapReply (pkt);
  219.  
  220.   if (SigMask & PipeMask)
  221.     while ((pkt= GetPkt (PipePort)) != NULL)
  222.       switch (pkt->dp_Type)
  223.         { case MODE_READWRITE:
  224. #ifdef DEBUG
  225.   OS ("Open READWRITE packet received\n");
  226. #endif DEBUG
  227.             OpenPipe (pkt, 0);
  228.             break;
  229.  
  230.           case MODE_READONLY:     /* syn: MODE_OLDFILE, ACTION_FINDINPUT */
  231. #ifdef DEBUG
  232.   OS ("Open READONLY packet received\n");
  233. #endif DEBUG
  234.             OpenPipe (pkt, 0);
  235.             break;
  236.  
  237.           case MODE_NEWFILE:     /* syn: ACTION_FINDOUTPUT */
  238. #ifdef DEBUG
  239.   OS ("Open NEWFILE packet received\n");
  240. #endif DEBUG
  241.             OpenPipe (pkt, 0);
  242.             break;
  243.  
  244.           case ACTION_END:
  245. #ifdef DEBUG
  246.   OS ("Close packet received\n");
  247. #endif DEBUG
  248.             ClosePipe (pkt);
  249.             break;
  250.  
  251.           case ACTION_READ:
  252. #ifdef DEBUG
  253.   OS ("<<< Read packet received\n");
  254. #endif DEBUG
  255.             StartPipeIO (pkt, PIPEREAD);
  256.             break;
  257.  
  258.           case ACTION_WRITE:
  259. #ifdef DEBUG
  260.   OS (">>> Write packet received\n");
  261. #endif DEBUG
  262.             StartPipeIO (pkt, PIPEWRITE);
  263.             break;
  264.  
  265. #if PIPEDIR
  266.           case ACTION_LOCATE_OBJECT:
  267. #  ifdef DEBUG
  268.      OS (  "Lock packet received\n");
  269. #  endif DEBUG
  270.             PipeLock (pkt);
  271.             break;
  272.  
  273.           case ACTION_COPY_DIR:
  274. #  ifdef DEBUG
  275.      OS (  "DupLock packet received\n");
  276. #  endif DEBUG
  277.             PipeDupLock (pkt);
  278.             break;
  279.  
  280.           case ACTION_FREE_LOCK:
  281. #  ifdef DEBUG
  282.      OS (  "UnLock packet received\n");
  283. #  endif DEBUG
  284.             PipeUnLock (pkt);
  285.             break;
  286.  
  287.           case ACTION_EXAMINE_OBJECT:
  288. #  ifdef DEBUG
  289.      OS (  "Examine packet received\n");
  290. #  endif DEBUG
  291.             PipeExamine (pkt);
  292.             break;
  293.  
  294.           case ACTION_EXAMINE_NEXT:
  295. #  ifdef DEBUG
  296.      OS (  "ExNext packet received\n");
  297. #  endif DEBUG
  298.             PipeExNext (pkt);
  299.             break;
  300.  
  301.           case ACTION_PARENT:
  302. #  ifdef DEBUG
  303.      OS (  "ParentDir packet received\n");
  304. #  endif DEBUG
  305.             PipeParentDir (pkt);
  306.             break;
  307. #endif PIPEDIR
  308.  
  309.           default:
  310. #ifdef DEBUG
  311.   OS ("BAD packet received, type = "); OL (pkt->dp_Type); NL;
  312. #endif DEBUG
  313.             pkt->dp_Res1= 0;
  314.             pkt->dp_Res2= ERROR_ACTION_NOT_KNOWN;
  315.             ReplyPkt (pkt);
  316.         }
  317.  
  318.   goto LOOP;
  319.  
  320.  
  321. QUIT:
  322.   DevNode->dn_Task= NULL;     /* bad if someone in process of accessing us . . . */
  323.  
  324.   if (TapReplyPort != NULL)
  325.     FreeMem (TapReplyPort, sizeof (struct MsgPort));     /* signal bit won't matter */
  326.  
  327. #ifdef DEBUG
  328.   CleanupDebugIO ();
  329. #endif DEBUG
  330.  
  331.   if (DOSBase != NULL)
  332.     CloseLibrary (DOSBase);
  333. }
  334.  
  335.  
  336.  
  337. /*---------------------------------------------------------------------------
  338. ** Returns the DosPacket associated with the next message on "port", or NULL
  339. ** if the port is empty.  The message is removed from the port.
  340. ** A related macro, ReplyPkt() is provided in pipe-handler.h.
  341. */
  342.  
  343. static struct DosPacket  *GetPkt (port)
  344.  
  345. register struct MsgPort  *port;
  346.  
  347. { register struct Message  *msg;
  348.  
  349.   return  ((msg= GetMsg (port)) == NULL)
  350.             ? NULL
  351.             : (struct DosPacket *) msg->mn_Node.ln_Name;
  352. }
  353.  
  354.  
  355.  
  356. /*---------------------------------------------------------------------------
  357. ** Searches "pipelist" for a pipe whose name is "name".  If found, a pointer
  358. ** to the pipe returns.  Otherwise, NULL returns.
  359. */
  360.  
  361. PIPEDATA  *FindPipe (name)
  362.  
  363. char  *name;
  364.  
  365. { PIPEDATA  *p;
  366.   char      *cp, *strdiff();
  367.  
  368.  
  369.   for (p= (PIPEDATA *) FirstItem (&pipelist); p != NULL; p= (PIPEDATA *) NextItem (p))
  370.     { cp= strdiff (name, p->name);
  371.  
  372.       if ((*cp == '\0') && (p->name[(LONG) cp - (LONG) name] == '\0'))
  373.         return p;     /* same name */
  374.     }
  375.  
  376.   return NULL;     /* no match found */
  377. }
  378.